Use GdkFrameClock for relayout
authorOwen W. Taylor <otaylor@fishsoup.net>
Tue, 18 Sep 2012 13:00:57 +0000 (09:00 -0400)
committerOwen W. Taylor <otaylor@fishsoup.net>
Thu, 14 Feb 2013 22:19:47 +0000 (17:19 -0500)
Add a ::layout signal to GdkFrameClock and use it instead of an idle
handler to drive the restyling and relayout of containers.

https://bugzilla.gnome.org/show_bug.cgi?id=685460

gdk/gdkframeclock.c
gdk/gdkframeclock.h
gtk/gtkcontainer.c
gtk/gtkcontainerprivate.h
gtk/gtkwidget.c

index 6b23ce632145c92c82f1172df92c9815a260770a..ca5484080d52a1a19a34fc427371b8145480b258 100644 (file)
@@ -79,6 +79,7 @@ G_DEFINE_INTERFACE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
 enum {
   FRAME_REQUESTED,
   BEFORE_PAINT,
+  LAYOUT,
   PAINT,
   AFTER_PAINT,
   LAST_SIGNAL
@@ -122,6 +123,23 @@ gdk_frame_clock_default_init (GdkFrameClockInterface *iface)
                   g_cclosure_marshal_VOID__VOID,
                   G_TYPE_NONE, 0);
 
+  /**
+   * GdkFrameClock::layout:
+   * @clock: the frame clock emitting the signal
+   *
+   * This signal is emitted immediately before the paint signal and
+   * indicates that the frame time has been updated, and signal
+   * handlers should perform any preparatory work before painting.
+   */
+  signals[LAYOUT] =
+    g_signal_new (g_intern_static_string ("layout"),
+                  GDK_TYPE_FRAME_CLOCK,
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
   /**
    * GdkFrameClock::paint:
    * @clock: the frame clock emitting the signal
@@ -279,6 +297,9 @@ gdk_frame_clock_paint (GdkFrameClock *clock)
   g_signal_emit (G_OBJECT (clock),
                  signals[BEFORE_PAINT], 0);
 
+  g_signal_emit (G_OBJECT (clock),
+                 signals[LAYOUT], 0);
+
   g_signal_emit (G_OBJECT (clock),
                  signals[PAINT], 0);
 
index 62124e2e7d2246e6848e18c63351240caee240bf..043a890514ca7fb6ad9c4742373607fe148f8291 100644 (file)
@@ -54,6 +54,7 @@ struct _GdkFrameClockInterface
   /* signals */
   /* void (* frame_requested)    (GdkFrameClock *clock); */
   /* void (* before_paint)       (GdkFrameClock *clock); */
+  /* void (* layout)             1(GdkFrameClock *clock); */
   /* void (* paint)              (GdkFrameClock *clock); */
   /* void (* after_paint)        (GdkFrameClock *clock); */
 };
index 4377a5f68396a4536e81eb56587b4baf0e46d0cd..938887ea1406a7625a2293364980c95a9df43059 100644 (file)
@@ -236,6 +236,9 @@ struct _GtkContainerPrivate
 {
   GtkWidget *focus_child;
 
+  guint resize_handler;
+  GdkFrameClock *resize_clock;
+
   guint border_width : 16;
 
   guint has_focus_chain    : 1;
@@ -344,8 +347,6 @@ static const gchar           vadjustment_key[] = "gtk-vadjustment";
 static guint                 vadjustment_key_id = 0;
 static const gchar           hadjustment_key[] = "gtk-hadjustment";
 static guint                 hadjustment_key_id = 0;
-static GSList               *container_resize_queue = NULL;
-static GSList               *container_restyle_queue = NULL;
 static guint                 container_signals[LAST_SIGNAL] = { 0 };
 static GtkWidgetClass       *parent_class = NULL;
 extern GParamSpecPool       *_gtk_widget_child_property_pool;
@@ -1357,10 +1358,15 @@ gtk_container_destroy (GtkWidget *widget)
 
   if (priv->resize_pending)
     _gtk_container_dequeue_resize_handler (container);
+
   if (priv->restyle_pending)
+    priv->restyle_pending = FALSE;
+
+  if (priv->resize_handler)
     {
-      container_restyle_queue = g_slist_remove (container_restyle_queue, container);
-      priv->restyle_pending = FALSE;
+      g_signal_handler_disconnect (priv->resize_clock, priv->resize_handler);
+      priv->resize_handler = 0;
+      priv->resize_clock = NULL;
     }
 
   if (priv->focus_child)
@@ -1553,7 +1559,6 @@ _gtk_container_dequeue_resize_handler (GtkContainer *container)
   g_return_if_fail (GTK_IS_CONTAINER (container));
   g_return_if_fail (container->priv->resize_pending);
 
-  container_resize_queue = g_slist_remove (container_resize_queue, container);
   container->priv->resize_pending = FALSE;
 }
 
@@ -1630,12 +1635,10 @@ gtk_container_set_reallocate_redraws (GtkContainer *container,
   container->priv->reallocate_redraws = needs_redraws ? TRUE : FALSE;
 }
 
-static gboolean
-gtk_container_idle_sizer (gpointer data)
+static void
+gtk_container_idle_sizer (GdkFrameClock *clock,
+                         GtkContainer  *container)
 {
-  GSList *slist;
-  gint64 current_time;
-
   /* We validate the style contexts in a single loop before even trying
    * to handle resizes instead of doing validations inline.
    * This is mostly necessary for compatibility reasons with old code,
@@ -1646,16 +1649,13 @@ gtk_container_idle_sizer (gpointer data)
    * sane values. So the result of an invalid style context will never be
    * a program crash, but only a wrong layout or rendering.
    */
-  current_time = g_get_monotonic_time ();
-  slist = container_restyle_queue;
-  container_restyle_queue = NULL;
-  while (slist)
+  if (container->priv->restyle_pending)
     {
-      GSList *next = slist->next;
-      GtkContainer *container = slist->data;
       GtkBitmask *empty;
+      gint64 current_time;
 
       empty = _gtk_bitmask_new ();
+      current_time = g_get_monotonic_time ();
 
       container->priv->restyle_pending = FALSE;
       _gtk_style_context_validate (gtk_widget_get_style_context (GTK_WIDGET (container)),
@@ -1663,8 +1663,6 @@ gtk_container_idle_sizer (gpointer data)
                                    0,
                                    empty);
 
-      g_slist_free_1 (slist);
-      slist = next;
       _gtk_bitmask_free (empty);
     }
 
@@ -1674,35 +1672,40 @@ gtk_container_idle_sizer (gpointer data)
    * than trying to explicitely work around them with some extra flags,
    * since it doesn't cause any actual harm.
    */
-  while (container_resize_queue)
+  if (container->priv->resize_pending)
     {
-      GtkContainer *container;
-
-      slist = container_resize_queue;
-      container_resize_queue = slist->next;
-      container = slist->data;
-      g_slist_free_1 (slist);
-
       container->priv->resize_pending = FALSE;
       gtk_container_check_resize (container);
     }
 
-  gdk_window_process_all_updates ();
-
-  return container_resize_queue != NULL || container_restyle_queue != NULL;
+  if (!container->priv->restyle_pending && !container->priv->resize_pending)
+    {
+      g_signal_handler_disconnect (clock, container->priv->resize_handler);
+      container->priv->resize_handler = 0;
+      container->priv->resize_clock = NULL;
+    }
+  else
+    {
+      gdk_frame_clock_request_frame (clock);
+    }
 }
 
 static void
 gtk_container_start_idle_sizer (GtkContainer *container)
 {
-  /* already started */
-  if (container_resize_queue != NULL ||
-      container_restyle_queue != NULL)
+  GdkFrameClock *clock;
+
+  if (container->priv->resize_handler != 0)
+    return;
+
+  clock = gtk_widget_get_frame_clock (GTK_WIDGET (container));
+  if (clock == NULL)
     return;
 
-  gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE,
-                             gtk_container_idle_sizer,
-                             NULL, NULL);
+  container->priv->resize_clock = clock;
+  container->priv->resize_handler = g_signal_connect (clock, "layout",
+                                                     G_CALLBACK (gtk_container_idle_sizer), container);
+  gdk_frame_clock_request_frame (clock);
 }
 
 static void
@@ -1725,7 +1728,6 @@ gtk_container_queue_resize_handler (GtkContainer *container)
             {
               container->priv->resize_pending = TRUE;
               gtk_container_start_idle_sizer (container);
-              container_resize_queue = g_slist_prepend (container_resize_queue, container);
             }
           break;
 
@@ -1780,8 +1782,6 @@ _gtk_container_queue_restyle (GtkContainer *container)
     return;
 
   gtk_container_start_idle_sizer (container);
-
-  container_restyle_queue = g_slist_prepend (container_restyle_queue, container);
   priv->restyle_pending = TRUE;
 }
 
@@ -1815,6 +1815,13 @@ _gtk_container_resize_invalidate (GtkContainer *container)
   _gtk_container_queue_resize_internal (container, TRUE);
 }
 
+void
+_gtk_container_maybe_start_idle_sizer (GtkContainer *container)
+{
+  if (container->priv->restyle_pending || container->priv->resize_pending)
+    gtk_container_start_idle_sizer (container);
+}
+
 void
 gtk_container_check_resize (GtkContainer *container)
 {
index f12148bb4fa08923cc0251cc9fde4ad96d07aa75..cd4bc5b2e9515fb5bb413c59c6181617d2a2983b 100644 (file)
@@ -39,6 +39,7 @@ GList *  _gtk_container_focus_sort             (GtkContainer     *container,
                                                 GtkWidget        *old_focus);
 gboolean _gtk_container_get_reallocate_redraws (GtkContainer *container);
 
+void      _gtk_container_maybe_start_idle_sizer (GtkContainer *container);
 
 G_END_DECLS
 
index a3509c4cc7884be32685fec64c90c63a4eccdb0b..e1cf124f688fbff7dc52565c4263caab0299b66f 100644 (file)
@@ -4585,6 +4585,9 @@ gtk_widget_realize (GtkWidget *widget)
       _gtk_widget_enable_device_events (widget);
       gtk_widget_update_devices_mask (widget, TRUE);
 
+      if (GTK_IS_CONTAINER (widget))
+        _gtk_container_maybe_start_idle_sizer (GTK_CONTAINER (widget));
+
       gtk_widget_pop_verify_invariants (widget);
     }
 }